home *** CD-ROM | disk | FTP | other *** search
- /*
- File: PrinterClassDriver.c
-
- Contains: MacOS USB printer class driver
- [ref. IEEE Std 1284-1994]
-
- Version: xxx put version here xxx
-
- Copyright: 1998 by Apple Computer, Inc., all rights reserved.
-
-
- */
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- includes
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- #include <Devices.h>
- #include <DriverServices.h>
- #include <Interrupts.h>
- #include <LowMem.h>
- #include <Folders.h>
- #include <String.h>
- #include <stdio.h>
- #include <USB.h>
-
- #ifndef __CODEFRAGMENTS__
- #include <codefragments.h>
- #endif
-
- #include "PrinterClassDriver.h"
- #include "TradDriverLoaderLib.h"
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- constants
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- #define MAX_SUFFIX 127 // maximum copies we'll enter in unit table
- #define kUSBParallelDrvrRsrcID 12
- #define kMinDrvrUnitNumber 48 // minimum unit table entry which we'll install
- #define kUSS720MillisecondDelay 3*1000 // poll every three seconds
-
- #define kUSBAttributeBulk 0x02
- #define kUSBInputEndpointMask 0x80
-
- enum
- {
- kCString = 0, // StateStr, USBStatusStr selector
- kPString, // StateStr, USBStatusStr selector
- kDrvrFirstDigit = 5 // length_byte + ".USB" = 5
- };
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- globals
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- struct usbPrinterPBStruct printerClassRecord;
- FSSpec printerClassDriverFileSpec;
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- prototypes
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-
- static void PrinterDeviceCompletionProc(USBPB *pb);
- static void SetNullUSBParamBlock( USBDeviceRef dev, USBPB *pb );
- static USBEndPointDescriptor *FindEndpoint( USBInterfaceDescriptor *pInterface, int endpointType );
- static void SoftReset( USBPB *usbprint, short interfaceNum );
- static void CapabilityRequest( USBPB *pb, Ptr p, long length, short config, short interfaceNum, short alternateSetting );
- static void CentronicsStatus( USBPB *usbprint, Ptr p, short interfaceNum );
-
- void PrinterDeviceInitiateTransaction(USBPB *pb);
-
- OSErr CFMInitialization( CFragInitBlock *initBlock );
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: HexStr
-
- Input Parameters:
- v unsigned long value
-
- Output Parameters:
- p 8 bytes: hex string representing value
-
- Description:
-
- Change History:
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- HexStr( unsigned long v, unsigned char *p )
- {
- int shift;
-
- for ( shift = 32-4; shift >= 0; shift -= 4 )
- {
- char c = (v >> shift) & 0x0F;
- *p++ = c + (c > 9? ('A'-10): '0');
- }
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: USBStatusStr
-
- Input Parameters:
- usbStatus usb error code
- kind kPString or kCString
-
- Output Parameters:
- unsigned char * description of error (c-string or p-string)
-
- Description:
- a simple mapping of errors to human-readable form
-
- Change History:
- 24 Apr 1998, oja: param to HexStr was off-by-one
- 26 Mar 1998, oja: added kStrPrintClass to catenated strings
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static unsigned char *
- USBStatusStr( OSStatus usbStatus, int kind )
- {
- unsigned char *p;
-
- switch ( usbStatus )
- {
- case kUSBInternalErr: p = "\p" kStrPrinterClass "Internal error"; break;
- case kUSBUnknownDeviceErr: p = "\p" kStrPrinterClass "Unknown device"; break;
- case kUSBUnknownPipeErr: p = "\p" kStrPrinterClass "Unknown pipe"; break;
- case kUSBTooManyPipesErr: p = "\p" kStrPrinterClass "Too many pipes"; break;
- case kUSBIncorrectTypeErr: p = "\p" kStrPrinterClass "Incorrect type"; break;
- case kUSBRqErr: p = "\p" kStrPrinterClass "Request error"; break;
- case kUSBUnknownRequestErr: p = "\p" kStrPrinterClass "Unknown request"; break;
- case kUSBTooManyTransactionsErr: p = "\p" kStrPrinterClass "Too many transactions"; break;
- case kUSBAlreadyOpenErr: p = "\p" kStrPrinterClass "Already open"; break;
- case kUSBNoDeviceErr: p = "\p" kStrPrinterClass "No device"; break;
- case kUSBDeviceErr: p = "\p" kStrPrinterClass "Device error"; break;
- case kUSBOutOfMemoryErr: p = "\p" kStrPrinterClass "Out of memory"; break;
- case kUSBNotFound: p = "\p" kStrPrinterClass "Not found"; break;
- case kUSBLinkErr: p = "\p" kStrPrinterClass "Link Err"; break;
- case kUSBCRCErr: p = "\p" kStrPrinterClass "Comms/Device err, bad CRC"; break;
- case kUSBBitstufErr: p = "\p" kStrPrinterClass "Comms/Device err, bitstuffing"; break;
- case kUSBDataToggleErr: p = "\p" kStrPrinterClass "Comms/Device err, Bad data toggle"; break;
- case kUSBEndpointStallErr: p = "\p" kStrPrinterClass "Device didn't understand"; break;
- case kUSBNotRespondingErr: p = "\p" kStrPrinterClass "No device, device hung"; break;
- case kUSBPIDCheckErr: p = "\p" kStrPrinterClass "Comms/Device err, PID CRC error"; break;
- case kUSBWrongPIDErr: p = "\p" kStrPrinterClass "Comms/Device err, Bad or wrong PID"; break;
- case kUSBOverRunErr: p = "\p" kStrPrinterClass "Packet too large or more data than buffer"; break;
- case kUSBUnderRunErr: p = "\p" kStrPrinterClass "Less data than buffer"; break;
- case kUSBRes1Err: p = "\p" kStrPrinterClass "kUSBRes1Err"; break;
- case kUSBRes2Err: p = "\p" kStrPrinterClass "kUSBRes1Err"; break;
- case kUSBBufOvrRunErr: p = "\p" kStrPrinterClass "Buffer over run error"; break;
- case kUSBBufUnderRunErr: p = "\p" kStrPrinterClass "Buffer under run error"; break;
- case kUSBNotSent1Err: p = "\p" kStrPrinterClass "Transaction not sent1"; break;
- case kUSBNotSent2Err: p = "\p" kStrPrinterClass "Transaction not sent2"; break;
- default:
- p = "\p" kStrPrinterClass "Unknown error nnnnnnnn";
- HexStr( usbStatus, p + *p - 8 + 1 );
- break;
- }
-
- return kind == kPString? p: p + 1;
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: StateStr
-
- Input Parameters:
- usbRefCon usb error code
- kind kPString or kCString
-
- Output Parameters:
- unsigned char * description of state (c-string or p-string)
-
- Description:
- a simple mapping of states to human-readable form
-
- Change History:
- 24 Apr 1998, oja: param to HexStr was off-by-one
- 26 Mar 1998, oja: added kStrPrintClass to catenated strings
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static unsigned char *
- StateStr( OSStatus refCon, int kind )
- {
- unsigned char *p;
-
- refCon &= ~(kTransactionPending | kRetryTransaction | kAsyncTransaction | kReturnFromDriver);
- switch ( refCon )
- {
- case kGetConfigurationDescriptor: p = "\p" kStrPrinterClass "kGetConfigurationDescriptor"; break;
- case kGetFullConfiguration: p = "\p" kStrPrinterClass "kGetFullConfiguration"; break;
- case kSetInterface: p = "\p" kStrPrinterClass "kSetInterface"; break;
- case kGetCapabilityString: p = "\p" kStrPrinterClass "kGetCapabilityString"; break;
- case kDelayGetCapability: p = "\p" kStrPrinterClass "kDelayGetCapability"; break;
- case kGetFullCapabilityString: p = "\p" kStrPrinterClass "kGetFullCapabilityString"; break;
- case kGetInterface: p = "\p" kStrPrinterClass "kGetInterface"; break;
- case kOpenBulkOutPipe: p = "\p" kStrPrinterClass "kOpenBulkOutPipe"; break;
- case kOpenBulkInPipe: p = "\p" kStrPrinterClass "kOpenBulkInPipe"; break;
- case kEnterNameRegistry: p = "\p" kStrPrinterClass "kEnterNameRegistry"; break;
- default:
- p = "\p" kStrPrinterClass "Unknown state nnnnnnnn";
- HexStr( refCon, p + *p - 8 + 1 );
- break;
- }
- return kind == kPString? p: p + 1;
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: HiHex
-
- Input Parameters:
- v only low byte used
-
- Output Parameters:
- <function result> high nibble represented as ASCII char
-
- Description:
-
- Change History:
- 20 Mar 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static unsigned char
- HiHex( int v )
- {
- unsigned char hinibble = (v >> 4) & 0x0f;
- return hinibble + ((hinibble > 9)? ('A'-10): '0');
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: LoHex
-
- Input Parameters:
- v only low byte used
-
- Output Parameters:
- <function result> low nibble represented as ASCII char
-
- Description:
-
- Change History:
- 20 Mar 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static unsigned char
- LoHex( int v )
- {
- unsigned char lonibble = v & 0x0f;
- return lonibble + ((lonibble > 9)? ('A'-10): '0');
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: immediateError
-
- Input Parameters:
-
- Output Parameters:
-
- Description:
-
- Change History:
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static Boolean
- immediateError(OSStatus err)
- {
- return((err != kUSBPending) && (err != noErr) );
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: SetNullUSBParamBlock
-
- Input Parameters:
- pb pointer to USB parameter block
- dev USB device reference
- Output Parameters:
- pb all fields set to default values
-
- Description:
- setup a USB parameter block for use by the current device
-
- Change History:
- 8 Jun 1998, oja: modified for new param blocks
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- SetNullUSBParamBlock( USBDeviceRef dev, USBPB *pb )
- {
- pb->qlink = NULL;
- pb->qType = 0;
- pb->pbLength = sizeof(USBPB);
- pb->pbVersion = kUSBCurrentPBVersion;
- pb->usbFlags = 0;
-
- pb->usbReference = dev;
- }
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: CountInterface
-
- Input Parameters:
- pConfigDesc pointer to USB device configuration string
- intClass USB class id
- intSubClass USB subclass id
-
- Output Parameters:
- <function result> number of interfaces which match the criteria
-
- Description:
- Count the number of interfaces (and alternates) which match the
- desired class and subclass.
-
- Change History:
- 26 Mar 1998, oja: use USBToHostWord to access length of
- Configuration Descriptor
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static int
- CountInterface(
- USBConfigurationDescriptorPtr pConfigDesc,
- int intClass,
- int intSubClass
- )
- {
- //
- // find an interface (and alternateSetting) which allows the desired class, subclass and protocol
- //
- int numInterfaces;
- UInt32 totalLength;
- void *pEndOfDescriptors;
- USBInterfaceDescriptorPtr pMyIntDesc;
- USBDescriptorHeaderPtr pCurrentDesc;
- Ptr p;
-
- totalLength = USBToHostWord( ((USBConfigurationDescriptorPtr)pConfigDesc)->totalLength );
- pEndOfDescriptors = (Ptr)pConfigDesc + totalLength; // get the total length and add it to the start of the config space
- pCurrentDesc = (USBDescriptorHeaderPtr)pConfigDesc; // point the currentdesc to the start of the config space
-
- numInterfaces = 0;
- while (pCurrentDesc < pEndOfDescriptors) // as long as we haven't exhausted all the descriptors
- {
- if (pCurrentDesc->descriptorType == kUSBInterfaceDesc) // look at the current descriptor
- {
- pMyIntDesc = (USBInterfaceDescriptorPtr)pCurrentDesc; // if it's an interface descriptor
- if (pMyIntDesc->interfaceClass == intClass &&
- pMyIntDesc->interfaceSubClass == intSubClass ) // see if it's the request descriptor
- {
- ++numInterfaces;
- }
- }
- if ( pCurrentDesc->length == 0 )
- {
- IF_DEBUG( DebugStr( "\pCountInterfaces NULL" ) );
- break;
- }
- p = (Ptr)pCurrentDesc + pCurrentDesc->length;
- pCurrentDesc = (USBDescriptorHeaderPtr) p; // Nope, that either wasn't an interface descriptor
- } // or it was, but not the droid we're looking for.
- return numInterfaces;
- }
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: FindInterface
-
- Input Parameters:
- pPrinterPB
- protocol (USB specification) protocol constant
-
- Output Parameters:
- pPrinterPB->pb.usbBuffer pointer to the interface
- pPrinterPB->pb.usbReqCount offset to the interface
-
- Description:
- Synchronous.
-
- find a print interface (and alternateSetting) which allows
- the desired protocol
-
- Note although USBFindNextInterfaceDescriptor returns immediately
- it still requires a completion routine.
-
- Change History:
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static struct USBInterfaceDescriptor *
- FindInterface( USBConfigurationDescriptorPtr pConfigDesc, int protocol )
- {
- //
- // find a print interface (and alternateSetting) which allows
- // the desired protocol
- //
- //
- int numInterfaces;
- UInt32 totalLength;
- void *pEndOfDescriptors;
- USBInterfaceDescriptorPtr pMyIntDesc;
- USBDescriptorHeaderPtr pCurrentDesc;
- Ptr p;
-
- totalLength = USBToHostWord( pConfigDesc->totalLength );
- pEndOfDescriptors = (Ptr)pConfigDesc + totalLength; // get the total length and add it to the start of the config space
- pCurrentDesc = (USBDescriptorHeaderPtr)pConfigDesc; // point the currentdesc to the start of the config space
-
- numInterfaces = 0;
- while (pCurrentDesc < pEndOfDescriptors) // as long as we haven't exhausted all the descriptors
- {
- if (pCurrentDesc->descriptorType == kUSBInterfaceDesc) // look at the current descriptor
- {
- pMyIntDesc = (USBInterfaceDescriptorPtr)pCurrentDesc; // if it's an interface descriptor
- if (pMyIntDesc->interfaceClass == kUSBPrintClass &&
- pMyIntDesc->interfaceSubClass == kUSBPrintSubClass &&
- pMyIntDesc->interfaceProtocol == protocol ) // see if it's the requested descriptor
- break;
- }
- if ( pCurrentDesc->length == 0 )
- {
- IF_DEBUG( DebugStr( "\pFindInterface NULL" ) );
- pCurrentDesc = pEndOfDescriptors; // shouldn't happen
- break;
- }
- p = (Ptr)pCurrentDesc + pCurrentDesc->length; // Nope, that either wasn't an interface descriptor
- pCurrentDesc = (USBDescriptorHeaderPtr) p;
- } // or it was, but not the droid we're looking for.
- return pCurrentDesc < pEndOfDescriptors? (struct USBInterfaceDescriptor *) pCurrentDesc: NULL;
-
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: FindEndpoint
-
- Input Parameters:
- pInterface pointer to interface descriptor
- kind kUSBIn, kUSBOut
-
- Output Parameters:
- result pointer to bulk endpoint descriptor
-
- Description:
-
- Change History:
- 8 Jun 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-
- static USBEndPointDescriptor *
- FindEndpoint( USBInterfaceDescriptor *pInterface, int kind )
- {
- USBEndPointDescriptor *pEndpoint = (USBEndPointDescriptor *) (pInterface->length + (Ptr) pInterface),
- *pEndOfEndpoints = pEndpoint + pInterface->numEndpoints;
-
- UInt8 addressMask = kind == kUSBIn? 0x80: 0;
- while ( pEndpoint < pEndOfEndpoints )
- {
- Ptr p = (Ptr) pEndpoint;
- if ( pEndpoint->attributes == 2 && ((pEndpoint->endpointAddress & addressMask) == addressMask) )
- break;
-
- p += pEndpoint->length;
- pEndpoint = (USBEndPointDescriptor *) p;
- }
-
- return pEndpoint < pEndOfEndpoints? pEndpoint: NULL;
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: ParseCapability
-
- Input Parameters:
- capability pointer to 1284-1994 capability string
- attribute pointer to c-string key we're retrieving (terminate with colon)
- *result_length maximum length of the result
-
- Output Parameters:
- result c-string which followed the key and was terminated by semi-colon
- (semi-colon has been stripped)
- *result_length actual length of the result (may be zero)
-
- Description:
- Search for "attribute" in the 1284 "capability" string
- The identifier is terminated with a semi-colon
-
- Return the attribute in result
- null-string if attribute not found.
-
- Change History:
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- ParseCapability(
- unsigned char *capability,
- unsigned char *attribute,
- unsigned char *result,
- int *result_length
- )
- {
- //
- // search for "attribute" in the 1284 "capability" string
- //
- // the identifier is terminated with a semi-colon
- //
- // return the attribute in result
- // null-string if attribute not found
- //
- // <to do> skip blanks, isolate colon, skip blanks
- //
- int source_length,
- target_length;
- unsigned char *source,
- *target,
- *destination;
- //
- // begin a brute force search
- //
- source = attribute;
- source_length = strlen((char *)attribute );
-
- target = capability + 3; // skip the length
- target_length = capability[1] | (capability[0] << 8);
- while ( target_length >= source_length )
- {
- if ( memcmp( source, target, source_length ) == 0 )
- break;
- --target_length;
- ++target;
- }
-
- destination = result;
- *destination = 0; // empty result
-
- target += source_length;
- target_length -= source_length; // skip the attribute string
-
- if ( target_length > 0 )
- {
- //
- // we found the attribute in the capability string
- //
- while ( destination - result < *result_length ) // arbitrarily limit reply
- {
- if ( *target == ';' )
- break;
- *destination++ = *target++; // copy a byte of attribute over
- }
- *destination++ = '\0'; // trailing NUL
- *result_length = destination - result; // report the length of the data (with trailing NUL)
- }
- }
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: GetClass
-
- Input Parameters:
- capability pointer to 1284-1994 capability string
- *result_length maximum length of the result
-
- Output Parameters:
- result c-string extracted from the MODEL key
- *result_length actual length of the result (may be zero)
-
- Description:
- CLASS is a Microsoft extension to the 1284-capability string
- if we don't find it
- we assume that the device is a printer
- Since the USB hardware has already indicated this, we're really allowing
- devices which aren't printers to be reached via the DRVRs we've installed.
-
- Change History:
- 26 Mar 1998, oja: result_length is output too
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- GetClass(
- unsigned char *capability,
- unsigned char *result,
- int *result_length
- )
- {
- //
- // We supply the upper-case PRINTER to be consistent with 1284-1994
- // if we don't find a class.
- //
- ParseCapability( capability, (unsigned char *) "CLASS:", result, result_length);
- if ( *result == '\0' )
- ParseCapability( capability, (unsigned char *) "CLS:", result, result_length);
- if ( *result == '\0' )
- strcpy( (char *)result, "PRINTER" );
- }
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: GetModel
-
- Input Parameters:
- capability pointer to 1284-1994 capability string
- *result_length maximum length of the result
-
- Output Parameters:
- result c-string extracted from the MODEL key
- *result_length actual length of the result (may be zero)
-
- Description:
- MODEL is a required field of the 1284-capability string
- MODEL may be abbreviated MDL
-
- Change History:
- 26 Mar 1998, oja: result_length is output too
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- GetModel(
- unsigned char *capability,
- unsigned char *result,
- int *result_length
- )
- {
- //
- // Most manufacturers abbreviate, so we search for MDL first
- //
- ParseCapability( capability, (unsigned char *) "MDL:", result, result_length );
- if ( *result == '\0' )
- ParseCapability( capability, (unsigned char *) "MODEL:", result, result_length );
- }
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: GetCommandSet
-
- Input Parameters:
-
- Output Parameters:
-
- Description:
-
- Change History:
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- GetCommandSet(
- unsigned char *capability,
- unsigned char *result,
- int *result_length
- )
- {
- //
- // COMMAND-SET is a required field of the 1284-capability string
- // COMMAND-SET may be abbreviated CMD
- //
- ParseCapability( capability, (unsigned char *) "CMD:", result, result_length );
- if ( *result == '\0' )
- ParseCapability( capability, (unsigned char *) "COMMAND-SET:", result, result_length );
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: GetManufacturer
-
- Input Parameters:
-
- Output Parameters:
-
- Description:
-
- Change History:
- 26 Jun 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- GetManufacturer(
- unsigned char *capability,
- unsigned char *result,
- int *result_length
- )
- {
- //
- // MANUFACTURER is a required field of the 1284-capability string
- // MANUFACTURER may be abbreviated MFG
- //
- ParseCapability( capability, (unsigned char *) "MFG:", result, result_length );
- if ( *result == '\0' )
- ParseCapability( capability, (unsigned char *) "MANUFACTURER:", result, result_length );
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: OpenBulkEndpoint
-
- Input Parameters:
- pPrinterPB
- pb
- refCon
-
- Output Parameters:
- pb->usbReference on (asynchronous) completion
-
- Description:
- Asynchronous completion.
-
- Open a bulkIn or bulkOut endpoint
-
- Change History:
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- OSStatus
- OpenBulkEndpoint(
- struct usbPrinterPBStruct *pPrinterPB,
- UInt32 refCon
- )
- {
-
- OSStatus err;
- USBEndPointDescriptor *eDesc;
- USBPB *pb = &pPrinterPB->pb;
- //
- // The params are set up correctly so open it
- // asynchronous completion will set usbReference to a pipe
- //
- switch (refCon)
- {
- case kOpenBulkOutPipe:
- eDesc = FindEndpoint( pPrinterPB->interface, kUSBOut );
- pPrinterPB->writeDescriptor = eDesc;
- pb->usbFlags = kUSBOut;
- break;
- case kOpenBulkInPipe:
- eDesc = FindEndpoint( pPrinterPB->interface, kUSBIn );
- pPrinterPB->readDescriptor = eDesc;
- pb->usbFlags = kUSBIn;
- break;
- default:
- USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "OpenEndpoint undefined refCon",1);
- break;
- }
- pb->pbVersion = kUSBCurrentPBVersion;
- pb->usbClassType = kUSBBulk;
- pb->usbOther = eDesc->endpointAddress & ~0x80;
- pb->usbWValue = USBToHostWord(eDesc->maxPacketSize);
- pb->usbRefcon = refCon | kTransactionPending | kAsyncTransaction;
-
- err = USBOpenPipe( pb );
- if(immediateError(err))
- USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "OpenEndpoint Failed Open pipe", 0);
-
- return err;
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: DeregisterDevice
-
- Input Parameters:
- pPrinterPB
-
- Output Parameters:
- <none>
-
- Description:
- remove the device from the name registry
-
- Change History:
- 11 Jun 1998, oja: test from RegistryCStrEntryLookup was wrong direction
- 17 Apr 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static OSStatus
- DeregisterDevice( struct usbPrinterPBStruct *pPrinterPB )
- {
- OSStatus err;
- RegEntryID self;
-
- RegistryEntryIDInit( &self );
- err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name , &self );
- if ( err == noErr )
- {
- err = RegistryEntryDelete( &self);
- }
- RegistryEntryIDDispose(&self);
- if (err == noErr && pPrinterPB->outRefNum != -1 )
- err = TradRemoveDriver( pPrinterPB->outRefNum, false );
- if (err == noErr && pPrinterPB->inRefNum != -1 )
- err = TradRemoveDriver( pPrinterPB->inRefNum, false );
-
- return err;
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: RegisterDevice
-
- Input Parameters:
- pPrinterPB
-
- Output Parameters:
- <none>
-
- Description:
- add the device into the name registry; we can't insert just the node
- if the parent nodes aren't present.
-
- if it isn't present
- insert the device CLASS into the registry
- if it isn't present
- insert the device MODEL into the registry
- finally insert the device itself into the registry
- we're careful to rename multiple devices
-
- Change History:
- 16 Jul 1998, oja: fix params to sprintf
- 8 Jun 1998, oja: don't use register param (CW build)
- 26 Mar 1998, oja: only register significant part of drvrNames
- log null model name to Expert
- register command set
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static OSStatus
- RegisterDevice( struct usbPrinterPBStruct *pPrinterPB )
- {
- //
- // add the device into the name registry
- // if it isn't present
- // insert the device CLASS into the registry
- // if it isn't present
- // insert the device MODEL into the registry
- // finally insert the device itself into the registry
- // we're careful to rename multiple devices
- //
- Str255 identification,
- devclass,
- model,
- commands;
- RegEntryID parent, where, self;
- OSStatus err;
- int model_length,
- command_length,
- class_length;
-
- class_length = sizeof(devclass);
- GetClass( pPrinterPB->capabilityString, devclass, &class_length );
-
- command_length = sizeof(commands);
- GetCommandSet(pPrinterPB->capabilityString, commands, &command_length );
-
- strcpy( (char *)pPrinterPB->name, (char *)"Devices:device-tree:" );
- strcat( (char *)pPrinterPB->name, (char *)devclass );
-
- RegistryEntryIDInit( &where );
- err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name, &where );
- if ( err == nrPathNotFound )
- {
- // class not in registry
- // create a node for all devices of this CLASS
- //
- RegistryEntryIDInit( &parent );
- err = RegistryCStrEntryLookup( nil, "Devices:device-tree:" , &parent );
- if ( err == noErr )
- err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->name, &where );
- RegistryEntryIDDispose(&parent);
-
- }
- //
- // add this model into the name registry of this class
- //
- if ( err == noErr )
- {
- model_length = sizeof(model);
- GetModel( pPrinterPB->capabilityString, model, &model_length );
- if ( model_length != 0 )
- {
- strcpy( (char *)pPrinterPB->name, "Devices:device-tree:" );
- strcat( (char *)pPrinterPB->name, (char *)devclass );
- strcat( (char *)pPrinterPB->name, ":" );
- strcat( (char *)pPrinterPB->name, (char *)model );
- RegistryEntryIDInit( &self );
- err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name , &self );
- if ( err != noErr )
- {
- // model not in registry
- err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->name, &self );
- }
- RegistryEntryIDDispose(&self);
- }
- }
- //
- // add this instance of this model of this class
- // into the name registry
- //
- if ( model_length == 0 )
- {
- //
- // possibly the cable isn't firmly connected or the printer isn't switched on
- //
- err = kUSBInternalErr;
- USBExpertFatalError(pPrinterPB->device, err, kStrPrinterClass "\pModel undefined", 0);
- }
- if ( err == noErr )
- {
- //
- // start off by identifying the device simply by the model name
- // increment the numeric suffix until we successfully registry the device
- //
- Str32 suffix;
- int numeric_suffix;
-
- strcpy( (char *)identification, (char *)model );
- RegistryEntryIDInit( &self );
- for ( numeric_suffix = 1; numeric_suffix < MAX_SUFFIX; ++numeric_suffix )
- {
- strcpy( (char *)pPrinterPB->name, "Devices:device-tree:" );
- strcat( (char *)pPrinterPB->name, (char *)devclass );
- strcat( (char *)pPrinterPB->name, ":" );
- strcat( (char *)pPrinterPB->name, (char *)model );
- strcat( (char *)pPrinterPB->name, ":" );
- strcat( (char *)pPrinterPB->name, (char *)identification );
- err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name , &self );
- if ( err != noErr )
- {
- // enter device in registry
- err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->name, &self );
- if ( err == noErr )
- err = RegistryPropertyCreate( &self, "drvrOut", &pPrinterPB->driverOutName, 1 + pPrinterPB->driverOutName[0] );
- if ( err == noErr )
- err = RegistryPropertyCreate( &self, "outRef", &pPrinterPB->outRefNum, sizeof(pPrinterPB->outRefNum) );
- if ( err == noErr )
- err = RegistryPropertyCreate( &self, "drvrIn", &pPrinterPB->driverInName, 1 + pPrinterPB->driverInName[0] );
- if ( err == noErr )
- err = RegistryPropertyCreate( &self, "inRef", &pPrinterPB->inRefNum, sizeof(pPrinterPB->inRefNum) );
- if ( err == noErr )
- err = RegistryPropertyCreate( &self, "privateData", &pPrinterPB, sizeof(pPrinterPB) );
- if ( err == noErr )
- err = RegistryPropertyCreate( &self, "read", &pPrinterPB->r, sizeof(QueueUSBReadUPP) );
- if ( err == noErr )
- err = RegistryPropertyCreate( &self, "write", &pPrinterPB->w, sizeof(QueueUSBWriteUPP) );
- if ( err == noErr && command_length > 0 )
- err = RegistryPropertyCreate( &self, "command-set", &commands, command_length );
- break;
- }
- //
- // if this name didn't succeed
- // try the next numeric suffix
- //
- sprintf( (char *)suffix, " %d", numeric_suffix );
- strcpy( (char *)identification, (char *)model );
- strcat( (char *)identification, (char *)suffix );
- }
- RegistryEntryIDDispose(&self);
- }
- USBExpertStatus( pPrinterPB->device, pPrinterPB->name, err );
- RegistryEntryIDDispose(&where);
-
- return err;
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: LoadResources
-
- Input Parameters:
- pPrinterPB pointer to class driver's private storage
-
- Output Parameters:
- OSStatus resource load error
-
- Description:
- Initialize time is the only safe time to to load resources from our file.
- Here's where we load resources and detach them from the resource manager.
- Later we'll use these private copies instead of GetResource calls.
-
- Using the file spec that we got from the CFMInitialization routine, open
- our resource fork.
-
- Change History:
- 11 Jun 1998, oja: removed hardcoded filename, use printerClassDriverFileSpec
- 20 Mar 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static OSStatus
- LoadResources( struct usbPrinterPBStruct *pPrinterPB )
- {
- short rf = -1; // class driver resource fork
- OSStatus err;
-
- //
- // open the resource fork of this class driver
- //
- rf = FSpOpenResFile( &printerClassDriverFileSpec,fsRdPerm );
- err = ResError();
-
- //
- // load the DRVR that we'll stick in the unit table
- //
- pPrinterPB->hDrvr = NULL;
- if ( err == noErr )
- {
- pPrinterPB->hDrvr = (DRVRHeaderHandle) Get1Resource( 'DRVR', kUSBParallelDrvrRsrcID );
- if ( pPrinterPB->hDrvr != NULL )
- DetachResource( (Handle) pPrinterPB->hDrvr );
- err = ResError();
- }
-
- if ( rf != -1 )
- CloseResFile( rf );
-
- return err;
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: InstallDrivers
-
- Input Parameters:
- pPrinterPB
-
- Output Parameters:
- OSStatus error code
-
- Description:
- install read and write drivers in the unit table
- we have separate drivers so that we can support a full-duplex protocol
- rename the driver we just installed (so multiple copies don't conflict)
- We use the DRVR -refnum-1 so that the driver name has the same hex chars
- as the driver number (for manual verification in MacsBug)
-
- Change History:
- 13 Jul 1998, oja: init err to noErr
- 26 Mar 1998, oja: Use refnum -1, use infix location to enumerate
- DRVR
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static OSStatus
- InstallDrivers( struct usbPrinterPBStruct *pPrinterPB )
- {
- //
- // install the driver in the unit table
- // rename the driver we just installed (so multiple copies don't conflict)
- //
- short refNum; // DRVR refNum
- OSStatus err = paramErr; // couldn't find driver
-
- if ( pPrinterPB->hDrvr != NULL )
- err = TradInstallDriverFromHandle( pPrinterPB->hDrvr, kMinDrvrUnitNumber, TradHighestUnitNumber() + 1, &pPrinterPB->outRefNum );
-
- if ( err == noErr )
- {
- UnitNumber unit;
- DriverFlags flags;
- DRVRHeaderPtr hdr;
- unsigned char *suffix, // append "In" and "Out"
- *infix; // driver reference number follows the ".USB"
-
- TradGetDriverInformation( pPrinterPB->outRefNum, &unit, &flags, pPrinterPB->driverOutName, &hdr );
- BlockMove( pPrinterPB->driverOutName, pPrinterPB->driverInName, 1 + pPrinterPB->driverOutName[0] );
-
- suffix = pPrinterPB->driverOutName + pPrinterPB->driverOutName[0] - 2;
- infix = pPrinterPB->driverOutName + kDrvrFirstDigit;
- infix[0] = HiHex( -pPrinterPB->outRefNum -1 );
- infix[1] = LoHex( -pPrinterPB->outRefNum -1 );
- suffix[0] = 'O';
- suffix[1] = 'u';
- suffix[2] = 't';
- TradRenameDriver( pPrinterPB->outRefNum, pPrinterPB->driverOutName );
- //
- // set the driver data to point to our parameter block
- //
- err = OpenDriver( pPrinterPB->driverOutName, &refNum );
- if ( err == noErr )
- {
- struct usbPrinterPBStruct *param = pPrinterPB;
- err = Control( refNum, kDrvrPrivateSetStorage, ¶m );
- CloseDriver( refNum );
- }
- err = TradInstallDriverFromHandle( pPrinterPB->hDrvr, kMinDrvrUnitNumber, TradHighestUnitNumber() + 1, &pPrinterPB->inRefNum );
- if ( err == noErr )
- {
-
- suffix = pPrinterPB->driverInName + pPrinterPB->driverInName[0] - 1;
- infix = pPrinterPB->driverInName + kDrvrFirstDigit;
- infix[0] = HiHex( -pPrinterPB->inRefNum -1 );
- infix[1] = LoHex( -pPrinterPB->inRefNum -1 );
- suffix[0] = 'I';
- suffix[1] = 'n';
- TradRenameDriver( pPrinterPB->inRefNum, pPrinterPB->driverInName );
- //
- // set the driver data to point to our parameter block
- //
- err = OpenDriver( pPrinterPB->driverInName, &refNum );
- if ( err == noErr )
- {
- struct usbPrinterPBStruct *param = pPrinterPB;
- err = Control( refNum, kDrvrPrivateSetStorage, ¶m );
- CloseDriver( refNum );
- }
- }
- }
-
- return err;
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: GetCapability
-
- Input Parameters:
-
- Output Parameters:
-
- Description:
- Asynchronous completion.
-
- Change History:
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- GetCapability( struct usbPrinterPBStruct *pPrinterPB, unsigned char *p, int length )
- {
- //
- // queue a transaction to retrieve the 1284 capability string
- // we must have assigned the interface by this point since the capability string
- // may vary with the interface
- //
- OSStatus err;
- USBPB *pb = &pPrinterPB->pb;
-
- pb->usbBMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
-
- pb->usbBRequest = kUSBPrintClassGetDeviceID;
- pb->usbWValue = (pPrinterPB->config)->configValue; // configuration
- pb->usbWIndex = ((pPrinterPB->interface)->interfaceNumber<<8) | (pPrinterPB->interface)->alternateSetting;
-
- pb->usbReqCount = length;
- pb->usbBuffer = p;
-
- pb->usbStatus = 0;
- pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
- pb->usbRefcon |= kTransactionPending | kAsyncTransaction;
-
- err = USBDeviceRequest(pb);
- if(immediateError(err))
- {
- USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "GetCapability", 0);
- }
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: IsLucentCable
-
- Input Parameters:
- dev USB device descriptor
-
- Output Parameters:
- Return 1 if the USB device is a USB-parallel cable
-
- Description:
-
-
- Change History:
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static int
- IsLucentCable( USBDeviceDescriptor *dev )
- {
- return ( USBToHostWord(dev->vendor) == 0x47E && USBToHostWord(dev->product) == 0x1001 )? 1: 0;
- }
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: SetInterface
-
- Input Parameters:
-
- Output Parameters:
-
- Description:
- Asynchronous completion.
-
- Change History:
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- SetInterface( USBPB *pb, int whichInterface, int whichAlternate )
- {
- //
- // the device is a Lucent USB-parallel cable
- // select the bi-directional interface
- OSStatus err;
-
- pb->usbBMRequestType = USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBInterface);
-
- pb->usbBRequest = kUSBRqSetInterface;
- pb->usbWValue = whichAlternate; // alternate setting
- pb->usbWIndex = whichInterface; // interface
-
- pb->usbReqCount = 0;
- pb->usbBuffer = NULL;
-
- pb->usbStatus = 0;
- pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
- pb->usbRefcon |= kTransactionPending | kAsyncTransaction;
-
- err = USBDeviceRequest(pb);
- if(immediateError(err))
- {
- USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "SetInterface", 0);
- }
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: GetInterface
-
- Input Parameters:
-
- Output Parameters:
-
- Description:
- Asynchronous completion.
-
- Change History:
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- GetInterface( USBPB *pb, UInt8 *alt )
- {
- //
- // make sure we account for any alternate interface currently in use by the device
- //
- OSStatus err;
-
- pb->usbBMRequestType = USBMakeBMRequestType(kUSBIn, kUSBStandard, kUSBInterface);
-
- pb->usbBRequest = kUSBRqGetInterface;
- pb->usbWValue = 0;
- pb->usbWIndex = 0;
-
- pb->usbReqCount = sizeof(UInt8); // single byte is requested
- pb->usbBuffer = alt;
-
- pb->usbStatus = 0;
- pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
- pb->usbRefcon |= kTransactionPending | kAsyncTransaction;
-
- err = USBDeviceRequest(pb);
- if(immediateError(err))
- {
- USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "GetInterface", 0);
- }
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: GetConfigurationDescriptor
-
- Input Parameters:
- pb USB parameter block
- pConfiguration storage for the reply
- length number of bytes allocated for the reply
-
- Output Parameters:
- pConfiguration the device's configuration descriptor (possibly truncated)
-
- Description:
- Asynchronous completion.
-
- Retrieve the device's configuration descriptor. Note that we may not get
- the full configuration--the client must read the length in the reply and
- determine if the call successfully completed retrieval of the full config-
- uration descriptor.
-
- Change History:
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- GetConfigurationDescriptor(
- USBPB *pb,
- USBConfigurationDescriptorPtr pConfiguration,
- int length
- )
- {
- OSStatus err;
-
- pb->usbBMRequestType = USBMakeBMRequestType(kUSBIn, kUSBStandard, kUSBDevice);
-
- pb->usbBRequest = kUSBRqGetDescriptor;
- pb->usbWValue = (kUSBConfDesc<<8) + 0;
- pb->usbWIndex = 0; //language
-
- pb->usbReqCount = length;
- pb->usbBuffer = pConfiguration;
-
- pb->usbStatus = 0;
- pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
- pb->usbRefcon |= kTransactionPending | kAsyncTransaction;
-
- err = USBDeviceRequest(pb);
- if(immediateError(err))
- {
- USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "GetConfigurationDescriptor", 0);
- }
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: ReadCompletion
-
- Input Parameters:
- pb USB parameter block
-
- Output Parameters:
- <none>
-
- Description:
- USB read requests complete here.
- We dequeue the MacOS DRVR read requests
-
- Change History:
- 8 Jun 1998, oja: clear stalls on error
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- ReadCompletion(USBPB *pb)
- {
- // call the user completion routine
- struct usbPrinterPBStruct *pPrinterPB = (struct usbPrinterPBStruct *) pb->usbRefcon;
- IOParamPtr clientParam = pPrinterPB->readDrvr.pb;
-
- clientParam->ioActCount = pb->usbActCount;
-
- if ( pb->usbStatus != noErr )
- {
- IF_DEBUG( USBExpertStatus(pPrinterPB->device, USBStatusStr(pb->usbStatus, kPString) , pb->usbStatus ) );
- USBClearPipeStallByReference(pb->usbReference); // we got an error, try to clear any stalls
- }
- clientParam->ioResult = pb->usbStatus;
-
- if ( pPrinterPB->writeDrvr.ctl != NULL )
- CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, pPrinterPB->readDrvr.ctl );
-
- pb->usbCompletion = NULL; // checked by Finalize
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: WriteCompletion
-
- Input Parameters:
- pb USB parameter block
-
- Output Parameters:
- <none>
-
- Description:
- USB write requests complete here.
- We dequeue the MacOS DRVR write requests
-
- Change History:
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- WriteCompletion(USBPB *pb)
- {
- // call the user completion routine
- struct usbPrinterPBStruct
- *pPrinterPB = (struct usbPrinterPBStruct *) pb->usbRefcon;
- IOParamPtr clientParam = pPrinterPB->writeDrvr.pb;
-
- clientParam->ioActCount = pb->usbActCount;
-
- if ( pb->usbStatus != noErr )
- {
- USBClearPipeStallByReference(pb->usbReference); // we got an error, try to clear any stalls
-
- IF_DEBUG( USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "WriteCompletion Error" , pb->usbStatus ) );
- IF_DEBUG( USBExpertStatus(pPrinterPB->device, USBStatusStr(pb->usbStatus, kPString) , pb->usbStatus ) );
-
- clientParam->ioResult = pb->usbStatus;
- }
-
- if ( pPrinterPB->writeDrvr.ctl != NULL )
- CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, pPrinterPB->writeDrvr.ctl );
-
- pb->usbCompletion = NULL; // checked by Finalize
-
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: QueueRead
-
- Input Parameters:
- pb MacOS device manager parameter block
- ctl device manager dCtl block
- pPrinterPB current printing device class's storage
-
- Output Parameters:
- <none>
-
- Description:
- MacOS DRVR read requests are re-queued here to the USB
- Since we only allow one read request pending at a time, we're able
- to use the USB refCon to point to our class driver's storage.
-
- Change History:
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- void
- QueueRead( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
- {
- OSStatus err;
- USBPB *usbprint = &pPrinterPB->in;
-
- #if DEBUG
- Str255 text;
-
- sprintf( (char *)text, " PrinterClass Read: %d @ %08x", pb->ioReqCount, pb->ioBuffer );
- text[0] = strlen((char *)text); // c2pstr
- USBExpertStatus(pPrinterPB->device, text, usbprint->usbStatus );
- #endif
- if ( printerClassRecord.terminating )
- pb->ioResult = abortErr;
- else
- {
-
- pPrinterPB->readDrvr.pb= pb;
- pPrinterPB->readDrvr.ctl = ctl;
- if ( pPrinterPB->readPipe != NULL )
- {
- SetNullUSBParamBlock( pPrinterPB->readPipe, usbprint );
- usbprint->usbBuffer = pb->ioBuffer;
- usbprint->usbReqCount = pb->ioReqCount;
- usbprint->usbRefcon = (unsigned long) pPrinterPB;
-
- usbprint->usbCompletion = (USBCompletion) ReadCompletion;
-
- pb->ioResult = ioInProgress;
- err = USBBulkRead( usbprint );
- if ( immediateError(err) )
- {
- IF_DEBUG( DebugStr( USBStatusStr(err, kPString) ) );
- usbprint->usbStatus = err;
- }
- }
- }
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: QueueWrite
-
- Input Parameters:
- pb MacOS device manager parameter block
- ctl device manager dCtl block
- pPrinterPB current printing device class's storage
-
- Output Parameters:
- <none>
-
- Description:
- MacOS DRVR write requests are re-queued here to the USB
- Since we only allow one read request pending at a time, we're able
- to use the USB refCon to point to our class driver's storage.
-
- Change History:
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- void
- QueueWrite( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
- {
- OSStatus err;
- USBPB *usbprint = &pPrinterPB->out;
-
- #ifdef DEBUG
- Str255 text;
- sprintf( (char *)text, " PrinterClass Write: %d @ %08x", pb->ioReqCount, pb->ioBuffer );
- text[0] = strlen((char *)text); // c2pstr
- USBExpertStatus(pPrinterPB->device, text, usbprint->usbStatus );
- #endif
-
- if ( printerClassRecord.terminating )
- pb->ioResult = abortErr;
- else
- {
- pPrinterPB->writeDrvr.pb = pb;
- pPrinterPB->writeDrvr.ctl = ctl;
- if ( pPrinterPB->writePipe != NULL )
- {
- SetNullUSBParamBlock( pPrinterPB->writePipe, usbprint );
- usbprint->usbBuffer = pb->ioBuffer;
- usbprint->usbReqCount = pb->ioReqCount;
- usbprint->usbRefcon = (unsigned long) pPrinterPB;
-
- usbprint->usbCompletion = (USBCompletion) WriteCompletion;
-
- pb->ioResult = ioInProgress;
-
- err = USBBulkWrite( usbprint );
- if ( immediateError(err) )
- {
- IF_DEBUG( DebugStr( USBStatusStr(err, kPString) ) );
- usbprint->usbStatus = err;
- }
- }
- }
- }
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: Abort
-
- Input Parameters:
- refNum DRVR refnum
- pPrinterPB current printing device class's storage
-
- Output Parameters:
-
- Description:
- Asynchronous completion.
-
- Change History:
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- OSStatus
- Abort( DriverRefNum refNum, struct usbPrinterPBStruct *pPrinterPB )
- {
- USBPipeRef whichPipe;
-
- whichPipe = refNum == pPrinterPB->outRefNum? pPrinterPB->writePipe: pPrinterPB->readPipe;
-
- return USBAbortPipeByReference( whichPipe );
- }
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: CompletionProc
-
- Input Parameters:
- pb USB param block ptr
-
- Output Parameters:
-
- Description:
- Asynchronous completion routine for DRVR requests.
-
- Change History:
- 11 Jun 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- CompletionProc(USBPB *pb)
- {
- // call the user completion routine
- struct usbPrinterPBStruct
- *pPrinterPB = (struct usbPrinterPBStruct *) pb->usbRefcon;
- IOParamPtr clientParam = pPrinterPB->statusDrvr.pb;
-
- clientParam->ioActCount = pb->usbActCount;
-
- if ( pb->usbStatus != noErr )
- {
- USBClearPipeStallByReference(pb->usbReference); // we got an error, try to clear any stalls
-
- IF_DEBUG( USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "CompletionProc Error" , pb->usbStatus ) );
- IF_DEBUG( USBExpertStatus(pPrinterPB->device, USBStatusStr(pb->usbStatus, kPString) , pb->usbStatus ) );
-
- clientParam->ioResult = pb->usbStatus;
- }
-
- if ( pPrinterPB->statusDrvr.ctl != NULL )
- CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, pPrinterPB->statusDrvr.ctl );
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: CentronicsStatus
-
- Input Parameters:
- pb MacOS device manager parameter block
- ctl device manager dCtl block
- pPrinterPB current printing device class's storage
-
- Output Parameters:
- pStatusByte
-
- Description:
- setup the device request for a USB printer class request one byte status.
-
- Change History:
- 29 Jun 1998, oja: called from StatusControlRequests, change params
- 26 Jun 1998, oja: changed params to be consistent w/ Read & Write
- 11 Jun 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- CentronicsStatus( USBPB *usbprint, Ptr buffer, short interfaceNumber )
- {
- usbprint->usbBMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
-
- usbprint->usbBRequest = kUSBPrintClassGetCentronicsStatus;
- usbprint->usbWValue = 0;
- usbprint->usbWIndex = interfaceNumber;
-
- usbprint->usbReqCount = 1;
- usbprint->usbBuffer = buffer;
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: SoftReset
-
- Input Parameters:
- usbprint USB param block
- interfaceNumber
-
- Output Parameters:
-
- Description:
- Setup the device request for a USB printer class request soft reset.
-
- Change History:
- 29 Jun 1998, oja: called from StatusControlRequests, change params
- 26 Jun 1998, oja: changed params to be consistent w/ Read & Write
- 11 Jun 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- void
- SoftReset( USBPB *usbprint, short interfaceNumber )
- {
- usbprint->usbBMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBOther);
-
- usbprint->usbBRequest = kUSBPrintClassSoftReset;
- usbprint->usbWValue = 0;
- usbprint->usbWIndex = interfaceNumber;
-
- usbprint->usbReqCount = 0;
- usbprint->usbBuffer = NULL;
-
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: CapabilityRequest
-
- Input Parameters:
- usbprint USB parameter block
- p result pointer
- length amount of data allocated
- config
- interfaceNum
- alternateSetting
-
-
- Output Parameters:
- p result pointer
- length amount of data allocated
-
- Description:
- setup the device request for a USB printer class request 1284 id string.
-
- Change History:
- 29 Jun 1998, oja: called from StatusControlRequests, change params
- 26 Jun 1998, oja: changed params to be consistent w/ Read & Write
- 11 Jun 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- void
- CapabilityRequest( USBPB *pb, Ptr p, long length, short configValue, short interfaceNumber, short alternateSetting )
- {
-
- pb->usbBMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
-
- pb->usbBRequest = kUSBPrintClassGetDeviceID;
- pb->usbWValue = configValue; // configuration
- pb->usbWIndex = (interfaceNumber<<8) | alternateSetting;
-
- pb->usbReqCount = length;
- pb->usbBuffer = p;
-
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: StatusControlRequests
-
- Input Parameters:
- pb MacOS device manager parameter block
- ctl device manager dCtl block
- pPrinterPB current printing device class's storage
-
- Output Parameters:
-
- Description:
- Asynchronous completion.
-
- Change History:
- 26 Jun 1998, oja: changed params to be consistent w/ Read & Write
- 11 Jun 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-
- void
- ControlStatusRequests( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
- {
-
- //
- // queue a transaction to retrieve the centronics status
- //
- OSStatus err;
- USBPB *usbprint = &pPrinterPB->pb;
- Boolean dosomething = false;
-
- #if DEBUG
- Str255 text;
-
- sprintf( (char *)text, " PrinterClass ControlStatus: %d", ((CntrlParam *) pb)->csCode );
- text[0] = strlen((char *)text); // c2pstr
- USBExpertStatus(pPrinterPB->device, text, usbprint->usbStatus );
- #endif
-
- switch( ((CntrlParam *) pb)->csCode )
- {
- case kDrvrCentronicsStatus:
- dosomething = true;
- CentronicsStatus( usbprint, *((Ptr *)((CntrlParam *) pb)->csParam), (pPrinterPB->interface)->interfaceNumber );
- break;
- case kDrvr1284IdString:
- dosomething = true;
- CapabilityRequest( usbprint,
- *((Ptr *)((CntrlParam *) pb)->csParam),
- *((long *) &((CntrlParam *) pb)->csParam[4]),
- (pPrinterPB->config)->configValue, // configuration
- (pPrinterPB->interface)->interfaceNumber,
- (pPrinterPB->interface)->alternateSetting );
- break;
- case kDrvrSoftReset:
- dosomething = true;
- SoftReset( usbprint, (pPrinterPB->interface)->interfaceNumber );
- break;
- default:
- break;
- }
-
- if ( !dosomething )
- pb->ioResult = paramErr;
- else
- {
- usbprint->usbStatus = 0;
- usbprint->usbCompletion = (USBCompletion)CompletionProc;
- usbprint->usbRefcon = (unsigned long) pPrinterPB;
-
- pb->ioResult = ioInProgress;
- pPrinterPB->statusDrvr.pb = pb;
- pPrinterPB->statusDrvr.ctl = ctl;
-
- err = USBDeviceRequest(usbprint);
- if(immediateError(err))
- {
- USBExpertFatalError(usbprint->usbReference, err, "\p" kStrPrinterClass "StatusControlRequests", 0);
- pb->ioResult = err;
- }
- }
- }
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: PrinterDeviceCompletionProc
-
- Input Parameters:
- pb refCon tells which state we're completing
-
- Output Parameters:
- <none>
-
- Description:
- Complete asynch transactions initiated by PrinterDeviceInitiateTransaction.
-
- Change History:
- 15 May 1998, oja: added missing break for GetCapabilityString
- reworked GetFullConfiguration to properly handle case
- where there's only one interface
- 26 Mar 1998, oja: set info 1 to DEBUG StateStr
- (distinguishes completion from initiate)
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-
- static void
- PrinterDeviceCompletionProc(USBPB *pb)
- {
- register struct usbPrinterPBStruct *pPrinterPB;
- int numInterface;
-
- pPrinterPB = (struct usbPrinterPBStruct *)(pb);
- pPrinterPB->transDepth--;
- if ((pPrinterPB->transDepth < 0) || (pPrinterPB->transDepth > 1))
- {
- USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "CompletionProc Illegal Transaction Depth", pPrinterPB->transDepth );
- }
-
- IF_DEBUG( USBExpertStatus(pPrinterPB->device, StateStr(pPrinterPB->pb.usbRefcon, kPString) , 1 ) );
- if((pPrinterPB->pb.usbStatus != noErr) && (pPrinterPB->pb.usbStatus != kUSBPending))
- {
- USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass " retry", pPrinterPB->pb.usbStatus);
-
- pPrinterPB->pb.usbRefcon &= ~(kTransactionPending + kAsyncTransaction + kReturnFromDriver);
- pPrinterPB->pb.usbRefcon |= kRetryTransaction;
- pPrinterPB->retryCount--;
- if (!pPrinterPB->retryCount)
- {
- USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "Retry failed", pPrinterPB->pb.usbRefcon & ~kRetryTransaction);
- pPrinterPB->pb.usbRefcon = kUndefined | kReturnFromDriver;
- return;
- } else {
- pPrinterPB->pb.usbStatus = noErr; // let's retry one more time
- }
- }
- else
- {
- pPrinterPB->pb.usbRefcon &= ~kRetryTransaction;
- pPrinterPB->retryCount = kPrinterRetryCount;
- }
-
- if (pPrinterPB->pb.usbRefcon & kTransactionPending)
- {
- int length;
-
- //
- // advance to the next state
- //
- pPrinterPB->pb.usbRefcon &= ~(kTransactionPending + kAsyncTransaction + kReturnFromDriver);
- switch(pPrinterPB->pb.usbRefcon)
- {
- case kGetConfigurationDescriptor:
- if ( pPrinterPB->pb.usbStatus == noErr )
- {
- pPrinterPB->pb.usbRefcon = kGetFullConfiguration;
- }
- break;
-
- case kGetFullConfiguration:
- if ( pPrinterPB->pb.usbStatus == noErr )
- {
- pPrinterPB->interface = FindInterface( pPrinterPB->config, kUSBPrintClassProtocolBidirectional );
- if ( pPrinterPB->interface == NULL )
- {
- pPrinterPB->interface = FindInterface( pPrinterPB->config, kUSBPrintClassProtocolUnidirectional );
- if ( pPrinterPB->interface == NULL )
- USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "Can't find protocol", 0);
- }
- if ( pPrinterPB->interface != NULL )
- pPrinterPB->interfaceOffset = (char *) pPrinterPB->interface - (char *) pPrinterPB->config;
-
- //
- // if there's only one interface (or alternate) supported
- // skip the attempt to assign the interface
- //
- numInterface = CountInterface( pPrinterPB->config, kUSBPrintClass, kUSBPrintSubClass );
- if ( numInterface <= 1 )
- pPrinterPB->pb.usbRefcon = kGetCapabilityString;
- else
- pPrinterPB->pb.usbRefcon = kSetInterface;
- }
- break;
-
- case kSetInterface:
- if ( pPrinterPB->pb.usbStatus == noErr )
- {
- SetNullUSBParamBlock(pPrinterPB->device, pb );
- pPrinterPB->pb.usbRefcon = kGetCapabilityString;
- }
- break;
-
- case kGetCapabilityString:
- if ( pPrinterPB->pb.usbStatus == noErr )
- {
- //
- // In the short term (fall '98) several vendors are planning on shipping
- // devices with a parallel port and using the Lucent USS-720 USB-to-parallel hardware.
- // Unfortunately this isn't an ideal solution from the USB perspective:
- // users can leave the printer off while the cable responds that there's
- // a printer connected. Then we have no way of using the DEVICE_ID
- // string to tag the printer and register it.
- // To alleviate this situation, we repeatedly poll the USS-720 if the DEVICE_ID
- // string is null. Every few seconds we'll retry this state.
- // At some point the user wants to print and switches on the printer. The class
- // driver then picks up from here and registers the device properly.
- //
- length = pPrinterPB->capabilityString[1] | (pPrinterPB->capabilityString[0] << 8);
- if ( IsLucentCable( &pPrinterPB->desc ) && pPrinterPB->pb.usbActCount == 0 )
- pPrinterPB->pb.usbRefcon = kDelayGetCapability;
- else
- pPrinterPB->pb.usbRefcon = kGetInterface;
- }
- else if ( pPrinterPB->pb.usbStatus == kUSBOverRunErr )
- {
- //
- // if we've haven't managed to read the whole capability string
- // we need to allocate memory and read it in by initiating kGetFullCapabilityString
- //
- length = pPrinterPB->capabilityString[1] | (pPrinterPB->capabilityString[0] << 8);
-
- if ( length > sizeof(pPrinterPB->capability) &&
- pPrinterPB->pb.usbRefcon == kGetCapabilityString )
- pPrinterPB->pb.usbRefcon = kGetFullCapabilityString;
- }
- break;
- case kDelayGetCapability:
- if ( pPrinterPB->pb.usbStatus == noErr )
- pPrinterPB->pb.usbRefcon = kGetCapabilityString;
- break;
- case kGetFullCapabilityString:
- if ( pPrinterPB->pb.usbStatus == noErr )
- pPrinterPB->pb.usbRefcon = kGetInterface;
- break;
- case kGetInterface:
- if ( pPrinterPB->pb.usbStatus == noErr )
- pPrinterPB->pb.usbRefcon = kOpenBulkOutPipe;
- break;
- case kOpenBulkOutPipe:
- if ( pPrinterPB->pb.usbStatus == noErr )
- {
- pPrinterPB->writePipe = pPrinterPB->pb.usbReference; // remember the ref
- pPrinterPB->out = pPrinterPB->pb;
- SetNullUSBParamBlock( pPrinterPB->device, &pPrinterPB->pb );
-
- if ( pPrinterPB->interface->interfaceProtocol == kUSBPrintClassProtocolBidirectional )
- pPrinterPB->pb.usbRefcon = kOpenBulkInPipe;
- else
- pPrinterPB->pb.usbRefcon = kEnterNameRegistry;
- }
- break;
- case kOpenBulkInPipe:
- if ( pPrinterPB->pb.usbStatus == noErr )
- {
- pPrinterPB->readPipe = pPrinterPB->pb.usbReference;
- pPrinterPB->in = pPrinterPB->pb;
- SetNullUSBParamBlock( pPrinterPB->device, &pPrinterPB->pb );
-
- pPrinterPB->pb.usbRefcon = kEnterNameRegistry;
- }
- break;
- case kNilCompletion:
- case kEnterNameRegistry:
- default:
- if ( pPrinterPB->pb.usbStatus == noErr )
- pPrinterPB->pb.usbRefcon = kUndefined | kReturnFromDriver;
- break;
- }
- }
-
- if ( pPrinterPB->terminating )
- {
- // if we've been hot unplugged
- // don't startup any new transactions
- // allow PrintDriverFinalize to continue
- pPrinterPB->pb.usbRefcon = kReturnFromDriver;
- }
- else if ( pPrinterPB->pb.usbStatus == noErr )
- {
- if (!(pPrinterPB->pb.usbRefcon & kReturnFromDriver))
- PrinterDeviceInitiateTransaction(pb);
- }
- else
- {
- USBExpertFatalError(pPrinterPB->device, pPrinterPB->pb.usbStatus, StateStr(pPrinterPB->pb.usbRefcon, kPString), pPrinterPB->pb.usbRefcon);
- USBExpertFatalError(pPrinterPB->device, pPrinterPB->pb.usbStatus, USBStatusStr(pPrinterPB->pb.usbStatus, kPString), 0);
- }
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: PrinterDeviceInitiateTransaction
-
- Input Parameters:
- pb USB parameter block
-
- Output Parameters:
-
- Description:
- Since USB transactions are asynchronous we use the refCon field
- in the parameter block to implement the following logic via a state machine.
-
- Start out by getting the device configuration descriptor
- If the device has more than one printing interface
- If a bidirectional interface exists
- select it
- Else
- select the (mandatory) unidirectional interface
- Get the (manadatory) 1284 capability string
- Open pipes to the BulkOut (and optional BulkIn) endpoints
- Install read and write drivers in the unit table
- Using information from the capability string
- enter the printer in the MacOS name registry.
-
-
- Change History:
- 15 May 1998, oja: cleanup error/status messages
- handle setinterface correctly if only one
- interface is available
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- void
- PrinterDeviceInitiateTransaction(USBPB *pb)
- {
- register struct usbPrinterPBStruct *pPrinterPB;
- int length;
- OSStatus err;
-
- pPrinterPB = (struct usbPrinterPBStruct *)(pb);
- pPrinterPB->transDepth++;
- if ((pPrinterPB->transDepth < 0) || (pPrinterPB->transDepth > 1))
- {
- USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "InitiateTransaction illegal transaction depth", 0);
- }
- IF_DEBUG( USBExpertStatus( pPrinterPB->device, StateStr(pPrinterPB->pb.usbRefcon, kPString), 0) );
-
- switch(pPrinterPB->pb.usbRefcon & ~kRetryTransaction)
- {
- case kGetConfigurationDescriptor:
- //
- // find the device's configuration information
- //
- pPrinterPB->config = (USBConfigurationDescriptorPtr) pPrinterPB->configuration;
- GetConfigurationDescriptor( &pPrinterPB->pb, pPrinterPB->config, sizeof(USBConfigurationDescriptor) );
- break;
-
- case kGetFullConfiguration:
- //
- // not enough room in statically allocated memory for device's configuration
- // try again after allocating enough memory
- // (memory is released on finalize)
- length = USBToHostWord( (pPrinterPB->config)->totalLength );
-
- pPrinterPB->config = MemAllocatePhysicallyContiguous ((ByteCount)length, true);
- GetConfigurationDescriptor( &pPrinterPB->pb, pPrinterPB->config, length );
- break;
- case kSetInterface:
- //
- // having identified the configuration
- // set the device to our prefered interface
- //
- SetInterface( &pPrinterPB->pb, pPrinterPB->interface->interfaceNumber, pPrinterPB->interface->alternateSetting );
- break;
- case kGetCapabilityString:
- //
- // once the interface (and alternate) is assinged
- // we can retreive the 1284 capability string to see what kind of printer
- // is attached
- pPrinterPB->capabilityString = pPrinterPB->capability;
- GetCapability( pPrinterPB, pPrinterPB->capabilityString, sizeof(pPrinterPB->capability) );
- break;
- case kDelayGetCapability:
- //
- // USS-720 USB-parallel cable: couldn't get the capability string because the printer is off
- // Delay a few seconds and try again.
- // Will succeed when the user turns the printer on.
- //
- pPrinterPB->pb.usbReqCount = kUSS720MillisecondDelay;
- pPrinterPB->pb.usbRefcon |= kTransactionPending | kAsyncTransaction;
- err = USBDelay(&pPrinterPB->pb);
- if(immediateError(err))
- {
- USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "kDelayGetCapability", 0);
- }
- break;
- case kGetFullCapabilityString:
- //
- // the capability string was too long to fit in the statically allocated space
- // need to release this memory when we finalize our driver
- //
- length = pPrinterPB->capability[1] | (pPrinterPB->capability[0]<<8);
-
- pPrinterPB->capabilityString = MemAllocatePhysicallyContiguous ((ByteCount)length, true);
- if ( pPrinterPB->capabilityString )
- GetCapability( pPrinterPB, pPrinterPB->capabilityString, length );
- else
- USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "Can't allocate capability", 0);
- break;
- case kGetInterface:
- // failsafe check that we've got the right setup
- // it's possible the device didn't respond to our SetInterface
- GetInterface( &pPrinterPB->pb, &pPrinterPB->whichAltInterface );
- break;
- case kOpenBulkOutPipe:
- //
- // open mandatory bulk out pipe
- //
- OpenBulkEndpoint( pPrinterPB, kOpenBulkOutPipe );
- break;
- case kOpenBulkInPipe:
- //
- // open optional bulk in pipe
- //
- OpenBulkEndpoint( pPrinterPB, kOpenBulkInPipe );
- break;
- case kEnterNameRegistry:
- //
- // once we know what device we're dealing with
- // open the i/o channel(s) to the device
- // and enter it in the name registry
- //
- err = InstallDrivers( pPrinterPB );
- if ( err == noErr )
- err = RegisterDevice( pPrinterPB );
- if ( err != noErr )
- USBExpertFatalError(pPrinterPB->device, err, "\p" kStrPrinterClass "RegisterDevice failed", 0);
- //
- // that's it
- // all other transactions proceed through QueueWrite and QueueRead
- // from the drivers we've installed in the unit table
- //
- pPrinterPB->pb.usbRefcon = kUndefined + kReturnFromDriver; // nothing else to do until we have i/o
- break;
- case kReturnFromDriver:
- break;
- default:
- USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "InitiateTransaction unknown transaction", 0);
- pPrinterPB->pb.usbRefcon = kUndefined + kReturnFromDriver;
- break;
- }
- }
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: PrintDriverEntry
-
- Input Parameters:
-
- Output Parameters:
-
- Description:
- This is where the system instantiates a USB printing device.
-
- We need to install drivers in the MacOS unitTable, and a reference
- in the name registry.
-
- But the information we need to do this is only available after some
- USB transactions have completed. So we initiate here a series of asynchronous
- USB operations to get that information (by calling the first
-
- Change History:
- 30 Jun 1998, oja: change CentronicsStatus to ControlStatusRequests
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- void
- PrintDriverEntry(
- USBDeviceRef device,
- USBDeviceDescriptorPtr desc,
- USBInterfaceDescriptorPtr pInterface
- )
- {
- static Boolean beenThereDoneThat = false;
- OSStatus err;
- RoutineDescriptor qw = BUILD_ROUTINE_DESCRIPTOR( uppQueueUSBWriteProcInfo, QueueWrite);
- RoutineDescriptor qr = BUILD_ROUTINE_DESCRIPTOR( uppQueueUSBReadProcInfo, QueueRead);
- RoutineDescriptor qa = BUILD_ROUTINE_DESCRIPTOR( uppAbortProcInfo, Abort);
- RoutineDescriptor qs = BUILD_ROUTINE_DESCRIPTOR( uppControlStatusProcInfo, ControlStatusRequests );
-
- if( !beenThereDoneThat)
- {
- beenThereDoneThat = true;
-
- printerClassRecord.desc = *desc; /* keep a copy of the device descriptor */
- if ( pInterface != NULL )
- printerClassRecord.interface = pInterface;
-
- printerClassRecord.device = device;
- printerClassRecord.transDepth = 0; /* init Delay Callback Depth */
-
- printerClassRecord.terminating = 0;
- printerClassRecord.out.usbCompletion = NULL;
- printerClassRecord.in.usbCompletion = NULL;
-
- printerClassRecord.inRefNum = -1; /* initially no DRVRs added to UnitTable */
- printerClassRecord.outRefNum = -1;
- err = LoadResources( &printerClassRecord );
- if ( err != noErr )
- USBExpertFatalError( device, err, "\p" kStrPrinterClass "LoadResources failed", 0);
- //
- // routines to write and read to the device must be called by 68K DRVR
- // so we use mixed-mode manager to dispatch between PPC and 68K
- //
- printerClassRecord.qwrite = (QueueUSBWriteUPP) &printerClassRecord.qwriteRD;
- printerClassRecord.qwriteRD = qw;
-
- printerClassRecord.qread = (QueueUSBReadUPP) &printerClassRecord.qreadRD;
- printerClassRecord.qreadRD = qr;
-
- printerClassRecord.qstatus = (ControlStatusUPP) &printerClassRecord.qstatusRD;
- printerClassRecord.qstatusRD = qs;
-
- printerClassRecord.qabort = (AbortUPP) &printerClassRecord.qabortRD;
- printerClassRecord.qabortRD = qa;
-
- printerClassRecord.r = (QueueUSBReadUPP) QueueRead;
- printerClassRecord.w = (QueueUSBWriteUPP) QueueWrite;
- printerClassRecord.s = (ControlStatusUPP) ControlStatusRequests;
- printerClassRecord.a = (AbortUPP) Abort;
-
- SetNullUSBParamBlock( device, &printerClassRecord.pb );
- SetNullUSBParamBlock( 0, &printerClassRecord.in ); // fill in pipe ref later
- SetNullUSBParamBlock( 0, &printerClassRecord.out ); // fill in pipe ref later
-
- /* Start out at first state */
- printerClassRecord.pb.usbRefcon = kGetConfigurationDescriptor;
- PrinterDeviceInitiateTransaction(&printerClassRecord.pb);
- }
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: PrintDriverFinalize
-
- Input Parameters:
-
- Output Parameters:
-
- Description:
- release any allocated storage
- remove DRVRs from the UnitTable
-
- One small complication happens when the USS-720 cable is used. It's possible
- that the user has the device plugged in, but the printer wasn't powered on.
- In this case, our state machine is still cycling between the states
- kDelayGetCapability and kGetCapabilityString. If we terminate before the delay
- returns we'll crash the system. We monitor terminating to handle this
-
- Change History:
- 12 Jul 1998, oja: allow for hot unplugging during initial startup
- wait for completion if refCon indicates some
- transaction is in progress
- 24 Apr 1998, oja: added call to DeregisterDevice
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- OSStatus
- PrintDriverFinalize( void )
- {
- UInt32 refCon = printerClassRecord.pb.usbRefcon & ~(kTransactionPending + kAsyncTransaction);
- OSStatus result = noErr;
- //
- // notify state machine not to continue
- //
- printerClassRecord.terminating = 1;
- //
- // abort and wait for any pending read/write/status calls
- //
- if ( printerClassRecord.in.usbCompletion != NULL )
- {
- USBAbortPipeByReference( printerClassRecord.readPipe );
- }
- if ( printerClassRecord.out.usbCompletion != NULL )
- {
- USBAbortPipeByReference( printerClassRecord.writePipe );
- }
- // wait for any outstanding startup transactions
- if ( refCon != kReturnFromDriver
- || printerClassRecord.out.usbCompletion != NULL
- || printerClassRecord.in.usbCompletion != NULL )
- result = (OSStatus) kUSBDeviceBusy;
- else
- {
- //
- // release any allocated storage
- //
- if ( printerClassRecord.capabilityString != printerClassRecord.capability )
- MemDeallocatePhysicallyContiguous( printerClassRecord.capabilityString );
-
- if ( (unsigned char *) printerClassRecord.config != printerClassRecord.configuration )
- MemDeallocatePhysicallyContiguous( printerClassRecord.config );
- //
- // remove printer from the name registry
- //
- DeregisterDevice( &printerClassRecord );
- }
-
- return result;
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: CFMInitialization
-
- Input Parameters:
- initBlock
-
- Output Parameters:
- printerClassDriverFileSpec set global
-
- Description:
- we use the code fragment initialization to get our filespec
- LoadResources will use to open our resource fork
-
- Change History:
- 11 Jun 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- OSErr
- CFMInitialization( CFragInitBlock *initBlock )
- {
- //
- // get a reference to our file so that we can open up the resource fork later on
- //
- if ( CFragHasFileLocation( initBlock->fragLocator.where ) )
- printerClassDriverFileSpec = *(initBlock->fragLocator.u.onDisk.fileSpec);
-
- return noErr;
- }
-
- // eof
-